<?php

/**
 * 生成可购买的藏品编号
 * 生成的编号介于 已购和最大限购中间,
 * 已购编号在 imt_1_favorite_sn 视图表中
 * $nowBuy : 此时购买的编号数组
 * $nowNms : 此时的购买数量
 * $max : 最大限购/ 发行量
 *
 * param :{'sn' =>'已成功购买编号列表', 'buy_nums'=>'已购买的数量','max'=>'此藏品的最大发售数量'}
 */

class CreateSn
{
    private $nowBuy;
    private $nowNms;
    private $max;
    private $lockSn;

    public function __construct($param)
    {
        $this->nowBuy = $param['sn'];
        $this->nowNms = $param['buy_nums'];
        $this->max = $param['max'];
        $this->lockSn = $param['lock'];
    }

    /**
     * @throws Exception
     */
    public function getResult()
    {
        $buyArr = [];
        $min = 0;
        if ($this->nowBuy) {
            $buyArr = explode(',', $this->nowBuy);
            $min = count($buyArr);
        }
        if ($this->lockSn) {
            $buyArr = $this->rankArr(array_merge($buyArr,$this->lockSn));
        }
        ### 如果次编号没购买过就直接返回首次编号
        if (empty($buyArr)) {
            return 1;
        }
        ### 不含上锁的编号的时候, 如果编码数量超过了售卖的数量 则报异常
        if ($this->nowNms < $min) {
            throw new Exception('藏品异常,请稍后下单');
        }
        $end = $this->max;
        ### 如果不是首次 , 则看现已售编号是否等于此时的购买值, 如果不等于则再此处查询可购买的编号
        if ($min < $buyArr[$min - 1]) {
            $min = 1;
            $end = $buyArr[$min - 1];
        }
        ### 如果购买数量等于购买的最大限度 ,返回最大值
        if ($this->isEnd()) {
            return $this->max;
        }
        $nums = $this->getNums($min, $end, $buyArr);
        if (empty($nums)) {
            return $this->getNums(1, $this->max, $buyArr);
        }
        return $nums;
    }

    // 判读最大值是否是最大号码
    private function isEnd(): bool
    {
        return $this->nowId == $this->max;
    }

    // 取值
    protected function getNums($start, $end, $buyArr = [])
    {
        for ($start; $start <= $end; $start++) {
            if (!in_array($start, $buyArr)) {
                return $start;
            }
        }
    }

    // 数组排序
    private function rankArr($buyArr)
    {
        usort($buyArr, function ($a, $b) {
            if ($a == $b) {
                return 0;
            }
            return ($a < $b) ? -1 : 1;
        });
        return $buyArr;
    }


}